package config

import (
	"encoding/json"
	"fmt"
	"gitee.com/liukexing/mqbroker/core/typedef"
	"io/ioutil"
	"log"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

var (
	Log        typedef.LogHandle = commLog
	ExecConfig typedef.ExecutionConfig
	Exit       chan int
	BasePath   = "./"
	Ext        = ".json"
	SChar      = "."
	NChar      = "/"
	ConfigName = ""
)

func init() {
	c, ok := GetConfig("config")
	if ok {
		BasePath = checknil(BasePath, c.Extend["path"].(string))
		Ext = checknil(Ext, c.Extend["ext"].(string))
		SChar = checknil(SChar, c.Extend["schar"].(string))
		NChar = checknil(NChar, c.Extend["nchar"].(string))
		ConfigName = checknil(NChar, c.Extend["configname"].(string))
	}
	initConfig()
}

func checknil(s string, r interface{}) string {
	if r != nil && r.(string) != "" {
		return r.(string)
	}
	return s
}

func initConfig() {
	c, ok := GetConfig(ConfigName)
	if !ok {
		return
	}
	c.Info.Enable = true
	ExecConfig.Info = c.Info
	typedef.Decode(c.Extend["config"], &ExecConfig.Config)
}

func CheckModule() bool {
	return !ExecConfig.Info.Enable
}

func getConfigPath(ConfigName string) string {
	return fmt.Sprintf("%s%s%s", BasePath,
		strings.Replace(ConfigName, SChar, NChar, -1), Ext)
}

func GetConfig(ConfigName string) (typedef.ConfigInfo, bool) {
	Config := typedef.ConfigInfo{Info: typedef.ModuleInfo{Module: ConfigName}}
	Info := Config.Info
	s, err := ioutil.ReadFile(getConfigPath(ConfigName))
	if CheckErr(typedef.ErrInfo{Info: Info, Err: err}) {
		return Config, false
	}
	if CheckErr(typedef.ErrInfo{Info: Info, Err: json.Unmarshal(s, &Config)}) {
		return Config, false
	}
	Config.Info.ID = typedef.GetUUID()
	Config.Info.Enable = GetEnable(ExecConfig.Config, strings.Split(Config.Info.Module, SChar), 0)
	return Config, true
}

func GetEnable(Config []typedef.ModuleConfig, module []string, deep int) bool {
	if len(module) < deep+1 {
		return false
	}
	for _, v := range Config {
		if v.Enable && v.Module == module[deep] {
			if deep+1 == len(module) {
				return v.Enable
			}
			return GetEnable(v.SubModule, module, deep+1)
		}
	}
	return false
}

func SetConfig(ConfigName string, Data typedef.ConfigInfo) bool {
	jsv, err := json.Marshal(Data)
	if CheckErr(typedef.ErrInfo{Info: Data.Info, Err: err}) {
		return false
	}
	if CheckErr(typedef.ErrInfo{Info: Data.Info, Err: ioutil.WriteFile(getConfigPath(ConfigName), jsv, 0644)}) {
		return false
	}
	return true
}

func commLog(info typedef.LoggerInfo) {
	log.Printf("[%s][%s][%s:%d:%s]%v\n", info.Type.Name, info.Info.Module, info.Run.File, info.Run.Line, info.Run.Func, info.Message)
}

func CheckErr(err typedef.ErrInfo) bool {
	if err.Err != nil {
		Log(typedef.LoggerInfo{
			Type:      typedef.ERROR,
			Info:      err.Info,
			Run:       runinfo(),
			Message:   err.Err,
			Timestamp: time.Now().Unix(),
		})
	}
	return err.Err != nil
}

func runinfo() typedef.LoggerRunInfo {
	run := typedef.LoggerRunInfo{
		File: "???",
		Line: 0,
		Func: "???",
	}
	pc, filename, line, ok := runtime.Caller(2)
	if ok {
		run.Func = filepath.Base(runtime.FuncForPC(pc).Name())
		run.File = filepath.Base(filename)
		run.Line = line
	}
	return run
}
